﻿using System.Collections.Generic;
using System.Linq;
using CardPlay.Model.ActionModel;
using CardPlay.Model.CardModel;
using CardPlay.Model.GameModel;
using CardPlay.Model.GameModel.Actions;

namespace CardPlay.DemoPack.Games.PairingVariants
{
    public abstract class PairingStyleGame : StandardCardGame
    {
        public const string FamilyName = "Pairing-style";

        protected PairingStyleGame()
        {
            MaximumDeals = 1;
            CardsPerDeal = 1;
            TotalFoundations = 0;
            TableauBuildSequence = CardFaceSequence.None;
        }

        public override bool ExecuteCommandAt(PartLocation location, bool auto)
        {
            if (Selection.Contains(location))
            {
                Selection.Remove(location);
                return true;
            }

            if (IsChangeSelectionAllowedAt(location))
            {
                Selection.Add(location);

                if (IsSelectionDiscardable(Selection))
                {
                    Execute(CreateRemoveSelectionAction());
                    Selection.Clear();
                }

                return true;
            }

            Selection.Clear();
            return base.ExecuteCommandAt(location, auto);
        }

        protected virtual IAction CreateRemoveSelectionAction()
        {
            return new ComplexAction(
                Selection
                    .OrderByDescending(l => l.Index)
                    .Select(selectedLocation => new RemoveCardAction(this, selectedLocation)));
        }

        public override int PercentComplete
        {
            get
            {
                var initialCount = CardsAtStart;
                var currentCount = CardPiles.Aggregate(0, (total, pile) => total + pile.Count);

                return 100 - (100 * currentCount) / initialCount;
            }
        }

        protected override bool IsComplete
        {
            get { return CardPiles.All(pile => pile.IsEmpty); }
        }

        protected override bool IsChangeSelectionAllowedAt(PartLocation location)
        {
            if (Selection.Contains(location)) return true;

            var pile = PileAt(location);

            return
                pile != null && location == pile.Top && pile.TopCard.IsFaceUp &&
                (   (Selection.Count == 0) ||
                    (Selection.Count == 1 && IsSelectionDiscardable(Selection.Concat(new[] { location }))));
        }

        protected virtual bool IsSelectionDiscardable(IEnumerable<PartLocation> selection)
        {
            return selection.Count() == 2 && selection.Select(location => CardAt(location).Rank).Distinct().Count() == 1;
        }

        protected override bool AllowedToPickupAtTableau(RemovePileAction action)
        {
            return false;
        }

        protected static bool SetHasPair(IEnumerable<CardPile> setOfPiles)
        {
            return setOfPiles.GroupBy(pile => pile.TopCard.Rank).Any(group => group.Count() > 1);
        }
    }
}